﻿using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Text;
using System.Threading;
using System.Threading.Tasks;
using Windows.Devices.Bluetooth;
using Windows.Devices.Bluetooth.GenericAttributeProfile;
using Windows.Foundation;
using Windows.Security.Cryptography;

namespace bleCore
{
    public class MyBleDevice
    {
        BluetoothLEDevice device;
        public string NAME { get;private set; }
        public string MAC { get; private set; }
        public string DEVICE_ID { get; private set; }

        public event DeviceConnectLost ConnectLost;
        IReadOnlyList<GattDeviceService> allService;
        List<GattCharacteristic> allCharacteristic;
        List<BleMsgReceiver> receivers = new List<BleMsgReceiver>();
        public DataReceivedEvent DataRecieved;
        public List<GattCharacteristic> UseCharacteristic { get; private set; }
        Guid[] _useCharacteristicUids;
        public List<GattCharacteristic> Writer = new List<GattCharacteristic>();
        public List<GattCharacteristic> Reader = new List<GattCharacteristic>();
        public List<GattCharacteristic> Indicater = new List<GattCharacteristic>();
        public List<GattCharacteristic> Notifier = new List<GattCharacteristic>();
        public MyBleDevice(BluetoothLEDevice Device, Guid[] useCharacteristicUids)
        {
            this.device = Device;
            this.device.ConnectionStatusChanged += Device_ConnectionStatusChanged;
            this.NAME = device.Name;
            this.MAC = Utility.MAC2String(device.BluetoothAddress);
            this.DEVICE_ID = device.DeviceId;
            this._useCharacteristicUids = useCharacteristicUids;
            findService();
        }

        private void Device_ConnectionStatusChanged(BluetoothLEDevice sender, object args)
        {
            if (sender.ConnectionStatus == BluetoothConnectionStatus.Disconnected)
            {
                Logger.LogDevice("设备{0}已掉线",this.MAC);
                if (ConnectLost != null)
                {
                    foreach (var handle in ConnectLost.GetInvocationList())
                    {
                        ((DeviceConnectLost)handle).Invoke(this);
                    }
                }
                foreach (var s in allService)
                {
                    s.Dispose();
                }
                device.Dispose();
            }
        }

        public async Task<GattCommunicationStatus> WriteAsync(string data)
        {
            return await WriteByteAsync(Encoding.ASCII.GetBytes(data+ '\n'));
        }
        public async Task<GattCommunicationStatus> WriteByteAsync(byte[] data)
        {
            if (Writer == null||Writer.Count==0)
            {
                throw new BleException("该设备不可写");
            }
            GattCharacteristic defaultWriter = null;
            if (Writer.Count > 0)
            {
                defaultWriter = Writer[0];
            }
            var status = await defaultWriter.WriteValueAsync(CryptographicBuffer.CreateFromByteArray(data), GattWriteOption.WriteWithoutResponse);
            return status;
        }
        private async void findService()
        {
            allCharacteristic = new List<GattCharacteristic>();
            UseCharacteristic = new List<GattCharacteristic>();
            var service = await this.device.GetGattServicesAsync();
            if (service.Status == GattCommunicationStatus.Success)
            {
                allService = service.Services;
                foreach (GattDeviceService ser in allService)
                {
                    string uuid = ser.Uuid.ToString();
                    findCharacteristic(ser);
                    Logger.LogDevice("DEVICE={1}SERVER={0}已被发现", ser.Uuid.ToString().Replace("-", ""), this.MAC);
                }
            }
            else
            {
                Logger.LogDevice("DEVICE={1}获取SERVER不成功,状态{0}", service.Status,this.MAC);
            }
        }

        private async void findCharacteristic(GattDeviceService gattDeviceService)
        {
            var characteristics = await gattDeviceService.GetCharacteristicsAsync();
            if (characteristics.Status == GattCommunicationStatus.Success)
            {
                
                foreach (var c in characteristics.Characteristics)
                {
                    allCharacteristic.Add(c);
                    Logger.LogDevice("DEV={1}#SRV={2}#GATT={0}已被发现", c.Uuid.ToString().Replace("-", ""), this.MAC, gattDeviceService.Uuid.ToString());
                }
                foreach (var use in _useCharacteristicUids)
                {
                    var gatt = allCharacteristic.FirstOrDefault(r => r.Uuid.CompareTo(use) == 0);
                    if (gatt != null)
                    {
                        setGatt(gatt);
                        Logger.LogDevice("{1}有效设备GATT={0}已被发现", gatt.Uuid.ToString().Replace("-", ""),this.MAC);
                    }
                }
            }
            else
            {
                Logger.LogSys("{0}取得GATT状态有误，状态码={1}",this.MAC, characteristics.Status);
            }
        }
        private void setGatt(GattCharacteristic gatt)
        {
            UseCharacteristic.Add(gatt);
            var w = gatt.CharacteristicProperties &
                (GattCharacteristicProperties.Write
                | GattCharacteristicProperties.WriteWithoutResponse
                | GattCharacteristicProperties.AuthenticatedSignedWrites
                | GattCharacteristicProperties.ReliableWrites);
            if (w != 0) Writer.Add(gatt);
            var r = gatt.CharacteristicProperties & 
                (GattCharacteristicProperties.Read);
            if (r != 0) Reader.Add(gatt);
            var n = gatt.CharacteristicProperties &
                (GattCharacteristicProperties.Notify);
            if (n != 0) Notifier.Add(gatt);
            var i = gatt.CharacteristicProperties &
                (GattCharacteristicProperties.Indicate);
            if (i != 0) Indicater.Add(gatt);
        }
        public void EnableGattReceive(string receive)
        {
            var receiver= BleMsgReceiver.GetReceiver(this, receive);
            if (!receivers.Contains(receiver)) {
                receiver.Connect();
                receiver.DataRecieved += dataReceived;
                receivers.Add(receiver); 
            }
        }
        private void dataReceived(MyBleDevice device, GattCharacteristic sender, byte[] data)
        {
            if (DataRecieved != null)
            {
                foreach (var handle in DataRecieved.GetInvocationList())
                {
                    ((DataReceivedEvent)handle).Invoke(device, sender, data);
                }
            }
        }
    }
}
